/**
 * 事件发布订阅类
 */
export default class EventEmitter {
  className = 'EventEmitter'; // 类名
  /**
   * 事件映射对象
   * @type {{ [key:string]: function[] }}
   */
  events = {};
  constructor() {
    // 定义事件映射对象标识属性
    Object.defineProperty(this.events, eventsSymbol, { value: true });
  }
  /**
   * 监听事件
   * @param {string} event
   * @param {function} listener
   * @returns
   */
  on(event, listener) {
    const listeners = this.events[event] || [];
    listeners.push(listener);
    this.events[event] = listeners;
    return this;
  }
  /**
   * 触发事件
   * @param {string} event
   * @param  {...*} args
   * @returns
   */
  emit(event, ...args) {
    const listeners = this.events[event] || [];
    listeners.forEach((listener) => listener.apply(this, args));
    return this;
  }
  /**
   * 取消监听
   * @param {string | undefined} event
   * @param {function | undefined} listener
   * @returns
   */
  off(event, listener) {
    // 未传入事件名，清空所有事件
    if (typeof event === 'undefined') Object.keys(this.events).forEach((key) => delete this.events[key]);
    // 未传入监听函数，清空指定事件名的所有事件
    else if (!listener) delete this.events[event];
    // 去除指定事件名的指定监听函数
    else {
      const listeners = this.events[event];
      this.events[event] = listeners && listeners.filter((i) => i !== listener);
    }
    return this;
  }
  /**
   * 监听事件一次
   * @param {string} event
   * @param {function} listener
   * @returns
   */
  once(event, listener) {
    this.on(event, (...args) => {
      listener.apply(this, args);
      this.off(event, listener);
    });
    return this;
  }
  /**
   * 获取所有的监听事件
   * @returns
   */
  getEvents() {
    return { ...this.events };
  }
}

// 监听事件对象标识属性
export const eventsSymbol = Symbol('EventEmitterEvents');
